Layout Exercises
Toggle, Revisited
Earlier, we saw how to build a <Toggle />
component using Framer Motion:
We solved it in that example using the animate
property, but now that we know about layout animations, there might be a better way!
Your mission is to update the code below so that it uses layout animations.
Acceptance Criteria:
- The
Toggle
component should not use theanimate
property. Instead, the ball's position should be controlled with CSS, and it should be animated using a layout animation.
Code Playground
import React from 'react';
import { motion } from 'framer-motion';
import styles from './Toggle.module.css';
function Toggle({ value, onChange, ...delegated }) {
return (
<button
type="button"
role="switch"
aria-checked={value}
className={styles.wrapper}
onClick={() => onChange(!value)}
{...delegated}
>
<motion.span
className={styles.ball}
initial={false}
transition={{
type: 'spring',
stiffness: 500,
damping: 40,
}}
animate={{
x: value ? '100%' : '0%',
}}
/>
</button>
);
}
export default Toggle;
Solution:
Flex Demo
Let's recreate the “FlexDemo” component from my blog post, An Interactive Guide to Flexbox!
Most of the code has already been provided. Your mission is to apply the Flexbox settings according to the state variables, and to animate it using Framer Motion.
Acceptance Criteria:
- The
flexDirection
,justifyContent
, andalignItems
state variables should be applied as an inline style to thedemoArea
element. - Framer Motion layout animations should be used to animate changing the various parameters.
- The text should not be distorted when switching between parameters (for example,
alignItems
should be able to switch betweenstretch
andcenter
without any text warping).
Code Playground
import React from 'react';
import { motion } from 'framer-motion';
import styles from './FlexDemo.module.css';
function FlexDemo() {
const [flexDirection, setFlexDirection] = React.useState('row');
const [justifyContent, setJustifyContent] =
React.useState('flex-start');
const [alignItems, setAlignItems] = React.useState('stretch');
return (
<section className={styles.wrapper}>
<div className={styles.demoArea}>
{ITEMS.map((item) => (
<div key={item.id} className={styles.flexItem}>
{item.label}
</div>
))}
</div>
<div className={styles.controls}>
<SelectControl
label="flex-direction"
value={flexDirection}
onChange={(event) => setFlexDirection(event.target.value)}
>
<option value="row">row</option>
<option value="column">column</option>
</SelectControl>
<SelectControl
label="justify-content"
value={justifyContent}
onChange={(event) =>
setJustifyContent(event.target.value)
}
>
<option value="flex-start">flex-start</option>
<option value="flex-end">flex-end</option>
<option value="center">center</option>
<option value="space-between">space-between</option>
<option value="space-around">space-around</option>
<option value="space-evenly">space-evenly</option>
</SelectControl>
<SelectControl
label="align-items"
value={alignItems}
onChange={(event) => setAlignItems(event.target.value)}
>
<option value="stretch">stretch</option>
<option value="flex-start">flex-start</option>
Solution: